﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Exchange.WebServices.Data;

namespace DeployForwardMailboxRules.Service
{
	/// <summary>
	/// Interface for Exchange operations.
	/// </summary>
	public interface IExchangeService
	{
		/// <summary>
		/// Deploys forward mailbox rule.
		/// </summary>
		/// <param name="emailAddress">User Mailbox address</param>
		/// <param name="forwardMailboxAddress">Forward Mailbox address</param>
		void DeployForwardMailboxRule(string emailAddress, string forwardMailboxAddress);

		/// <summary>
		/// Checks whether rule already exists in Mailbox or not.
		/// </summary>
		/// <param name="emailAddress">User Mailbox address.</param>
		/// <param name="forwardMailboxAddress">Forward Mailbox address.</param>
		/// <returns>true if exists, false otherwise.</returns>
		bool IsForwardRuleExists(string emailAddress, string forwardMailboxAddress);

		/// <summary>
		/// Deletes Forward Mailbox rule if already exists.
		/// </summary>
		/// <param name="emailAddress">User Mailbox Address</param>
		/// <param name="forwardMailboxAddress">Forward Mailbox Address</param>
		void DeleteForwardMailboxRule(string emailAddress, string forwardMailboxAddress);
	}

	/// <summary>
	/// Base class for Common operations between various variants of Exchange.
	/// </summary>
	public abstract class ExchangeServiceBase : IExchangeService
	{
		protected abstract ExchangeService ExchService { get; }
		private const string ForwardMailboxRuleName = "MSCRMForward{0}";

		public void DeployForwardMailboxRule(string emailAddress, string forwardMailboxAddress)
		{
			string forwardRuleName = String.Format(ForwardMailboxRuleName, forwardMailboxAddress);
			//Getting exchange service.
			ExchangeService service = ExchService;
			service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, emailAddress);

			//Retrieving rules to check if forward mailbox rule already exists.
			RuleCollection ruleCollection = service.GetInboxRules(emailAddress);
			foreach (Rule rule in ruleCollection)
			{
				if (String.Equals(rule.DisplayName, forwardRuleName, StringComparison.OrdinalIgnoreCase))
				{
					//Rule already exists and hence returning.
					return;
				}
			}

			//Rule doesn't exist and hence creating new rule.
			Rule fwdRule = new Rule();
			fwdRule.DisplayName = forwardRuleName;
			fwdRule.Priority = 1;
			fwdRule.IsEnabled = true;
			fwdRule.Conditions.SentToOrCcMe = true;
			fwdRule.Actions.ForwardAsAttachmentToRecipients.Add(forwardMailboxAddress);

			CreateRuleOperation createOperation = new CreateRuleOperation(fwdRule);
			service.UpdateInboxRules(new RuleOperation[] { createOperation }, true, emailAddress);
			//New forward mailbox rule created.
		}

		public bool IsForwardRuleExists(string emailAddress, string forwardMailboxAddress)
		{
			string forwardRuleName = String.Format(ForwardMailboxRuleName, forwardMailboxAddress);

			//Getiing exchange service.
			ExchangeService service = ExchService;
			service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, emailAddress);

			//Retrieving rules to check if forward mailbox rule already exists.
			RuleCollection ruleCollection = service.GetInboxRules(emailAddress);
			foreach (Rule rule in ruleCollection)
			{
				if (String.Equals(rule.DisplayName, forwardRuleName, StringComparison.OrdinalIgnoreCase))
				{
					//Rule already exists and hence returning.
					return true;
				}
			}
			return false;
		}

		public void DeleteForwardMailboxRule(string emailAddress, string forwardMailboxAddress)
		{
			string forwardRuleName = String.Format(ForwardMailboxRuleName, forwardMailboxAddress);

			//Getiing exchange service.
			ExchangeService service = ExchService;
			service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, emailAddress);

			//Retrieving rules to check if forward mailbox rule already exists.
			RuleCollection ruleCollection = service.GetInboxRules(emailAddress);
			foreach (Rule rule in ruleCollection)
			{
				if (String.Equals(rule.DisplayName, forwardRuleName, StringComparison.OrdinalIgnoreCase))
				{
					//Rule exists and hence deleting.
					DeleteRuleOperation deleteOperation = new DeleteRuleOperation(rule.Id);
					service.UpdateInboxRules(new RuleOperation[] { deleteOperation }, true, emailAddress);
					return;
				}
			}
		}
	}
}
